/******************************************************************************************************
Copyright (C) 2013 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals FileDialog, Dir, settings, serialization, File, MessageBox, qsTr, Application, ProgressDialog, TextStream, Str, Molecule, DBDefinition, print, MnUi*/
/*jslint plusplus: true, indent: 4*/

function dbSDFileToDefinition() {
	"use strict";
	var inFileName, inFile, inStream, outFileName, outFile, outStream, tempFile, tempFileName, tempFileNamePrefix, molCountString,
		progress, line, startTime, buffer, dw, i,
		endConnectionTableWritten, tagFields, tagLengths, l,
		molecule, tagNames, n, tagName, tagData, tagType, dbDef, newTagName, fieldLength,
		molCount = 0,
		ok = true,
		progressLabel = qsTr("Reading file ...\n{0} Molecules\n{1} of {2} characters read"),
	// Save value of FileHistory setting
		oldFileHistory = serialization.fileHistory,
	// Settings keys
		inFileSettingsKey = "Database/SDFile to Definition/Input File",
		outFileSettingsKey = "Database/SDFile to Definition/Output File";

	// Prompt for input file 
	inFileName = FileDialog.getOpenFileName("SDfile (*.sdf);;All files (*.*)", qsTr("Select Input File"), settings.value(inFileSettingsKey, Dir.home()));
	if (!inFileName.length) {
		return;
	}
	settings.setValue(inFileSettingsKey, inFileName);

	// Check that input file is readable
	serialization.fileHistory = false;
	inFile = new File(inFileName);
	if (!inFile.open(File.ReadOnly)) {
		MessageBox.critical(qsTr("Could not open file '{0}'.").format(inFileName));
		return;
	}

	// Prompt for output file
	outFileName = FileDialog.getSaveFileName("Database definition (*.xml);;All files (*.*)",
			qsTr("Select Output File"),
			settings.value(outFileSettingsKey, Dir.home() + "/" + Str.fileNameFromPath(inFileName, false) + ".xml"));
	if (!outFileName.length) {
		return;
	}
	settings.setValue(outFileSettingsKey, outFileName);

	// Process file
	startTime = new Date();
	inStream = new TextStream(inFile);
	tempFileNamePrefix = Dir.temp() + "/" + Str.fileNameFromPath(inFileName) + "-";
	buffer = [];
	endConnectionTableWritten = false;

	progress = new ProgressDialog();
	progress.setRange(0, inFile.size);
	progress.value = 0;
	progress.labelText = progressLabel.format(0, 0, inFile.size);
	progress.show();
	Application.mainWindow.processEvents();

	tagFields = {};
	tagLengths = {};

	while (!inStream.atEnd() && ok && !progress.wasCanceled) {

		line = inStream.readLine();
		//print("'" + line + "'");
		if (line === "$$$$") {


			// Issue #1539: Add "M  END" to connection table
			if (!endConnectionTableWritten) {
				buffer.push("M  END");
			}

			// Write temporary file
			molCount++;
			molCountString = molCount.toString();
			while (molCountString.length < 6) {
				molCountString = "0" + molCountString;
			}
			tempFileName = tempFileNamePrefix + molCountString + ".sdf";
			//print("Writing file " + outFileName);
			tempFile = new File(tempFileName);
			tempFile.open(File.WriteOnly);
			outStream = new TextStream(tempFile);
			for (l = 0; l < buffer.length; l++) {
				outStream.writeln(buffer[l]);
			}
			outStream.writeln("$$$$");
			tempFile.close();

			// Open and scan sdf tags
			dw = Application.mainWindow.newDocument();
			if (serialization.open(tempFileName, "sdf")) {
				//progress.value++;


				//print(" Opened ok: " + dw.getMolTableItemCount() + " items.");
				for (i = 0; i < dw.getMolTableItemCount(); i++) {
					molecule =  new Molecule(dw.getMolTableItem(i));
					tagNames = molecule.sdfNames();
					for (n = 0; n < tagNames.length; n++) {
						tagName = tagNames[n];
						tagData = molecule.getSDFData(tagName);
						//print("  " + n + " " + tagName + " :'" + tagData + "'");
						tagType = "TEXT";
						if (!isNaN(tagData)) {
							if (parseFloat(tagData) === parseInt(tagData, 10)) {
								tagType = "INTEGER";
							} else {
								tagType = "NUMERIC";
							}
						}
						if (tagFields[tagName] === undefined
								|| (tagFields[tagName] === "INTEGER" && (tagType === "TEXT" || tagType === "NUMERIC"))
								|| (tagFields[tagName] === "NUMERIC" && tagType === "TEXT")) {
							tagFields[tagName] = tagType;
						}
						tagLengths[tagName] = Math.max(tagLengths[tagName] === undefined ? 0 : tagLengths[tagName], tagData.toString().length);
					}
				}
				tempFile.remove();
			} else {
				Application.mainWindow.endBusy();
				//progress.hide();
				MessageBox.critical(qsTr("Error while reading file '{0}'.").format(tempFileName));
				ok = (MessageBox.question(qsTr("Continue with Import?"), MessageBox.Yes, MessageBox.No) === MessageBox.Yes);
				Application.mainWindow.setBusy(qsTr("Working..."));
				//progress.show();
			}
			dw.close();
			buffer = [];
			endConnectionTableWritten = false;


		} else if (line === "M END" || line === "M  END") {
			buffer.push("M  END");
			endConnectionTableWritten = true;

		} else {
			if (line.substr(0, 1) === ">" && !endConnectionTableWritten) {
				// Issue #1539: Add "M END" to connection table
				buffer.push("M  END");
				endConnectionTableWritten = true;
			}
			buffer.push(line);
		}

		progress.value = inStream.pos;
		progress.labelText = progressLabel.format(molCount + 1, inStream.pos, inFile.size);
		Application.mainWindow.processEvents();
	}
	inFile.close();

	dbDef = DBDefinition.defaultDefinition("sdfDatabase");
	for (tagName in tagFields) {
		if (tagFields.hasOwnProperty(tagName)) {
			//print("tag '" + tagName + "': " + tagFields[tagName] + " (" + tagLengths[tagName] + ")");
			newTagName = tagName;
			while (dbDef.hasField("Molecule", newTagName)) {
				newTagName += "_1";
			}
			fieldLength = tagFields[tagName] === "TEXT" ? (tagLengths[tagName] < 90 ? 100 : 65535) : 0;
			dbDef.addField("Molecule", newTagName, tagFields[tagName], fieldLength, "=Molecule(item).getSDFData(\"" + tagName + "\")", "");
		}
	}

	//print(dbDef.toXml());

	outFile = new File(outFileName);
	outFile.open(File.WriteOnly);
	outStream = new TextStream(outFile);
	outStream.write(dbDef.toXml());
	outFile.close();

	progress.close();
	Application.mainWindow.endBusy();
	serialization.fileHistory = oldFileHistory;
	MessageBox.information(qsTr("Database definition from {0} molecules written to <b>{1}</b>.").format(molCount, outFileName));
	print("All done in " + ((new Date() - startTime) / 1000) + " seconds.");
}

if (this.MnUi && MnUi.scripts_db) {
	MnUi.scripts_db.scripts_db_SDFileToDefinition = dbSDFileToDefinition;
}
